package org.zing.proxy.test02;

import java.lang.invoke.MethodHandles;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

/**
 * @Author zqx
 * @Date 2024-04-22
 */

// 1.实现 Performance 接口
public final class ProxyAgent extends Proxy implements Performance {
    private static final Method m0;
    private static final Method m1;
    private static final Method m2;
    private static final Method m3;

    // 2.把我们提供了的匿名内部类对象传递给了父类
    public ProxyAgent(InvocationHandler invocationHandler) {
        super(invocationHandler);
    }

    static {
        ClassLoader classLoader = ProxyAgent.class.getClassLoader();

        try {
            m0 = Class.forName("java.lang.Object", false, classLoader)
                    .getMethod("hashCode", new Class[0]);


            m1 = Class.forName("java.lang.Object", false, classLoader)
                    .getMethod("equals", Class.forName("java.lang.Object", false, classLoader));

            m2 = Class.forName("java.lang.Object", false, classLoader)
                    .getMethod("toString", new Class[0]);

            m3 = Class.forName("org.zing.proxy.test02.Performance", false, classLoader)
                    .getMethod("sing", Class.forName("java.lang.String", false, classLoader));
        } catch (NoSuchMethodException noSuchMethodException) {
            throw new NoSuchMethodError(noSuchMethodException.getMessage());
        } catch (ClassNotFoundException classNotFoundException) {
            throw new NoClassDefFoundError(classNotFoundException.getMessage());
        }
    }

    @Override
    public final boolean equals(Object object) {
        try {
            return (Boolean)this.h.invoke(this, m1, new Object[]{object});
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    @Override
    public final String toString() {
        try {
            return (String)this.h.invoke(this, m2, null);
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    @Override
    public final int hashCode() {
        try {
            return (Integer)this.h.invoke(this, m0, null);
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    @Override
    public final String sing(String string) {
        try {
            return (String)this.h.invoke(this, m3, new Object[]{string});
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    private static MethodHandles.Lookup proxyClassLookup(MethodHandles.Lookup lookup)
            throws IllegalAccessException {

        if (lookup.lookupClass() == Proxy.class && lookup.hasFullPrivilegeAccess()) {
            return MethodHandles.lookup();
        }
        throw new IllegalAccessException(lookup.toString());
    }
}
